package com.example.authsystem.service;

import com.example.authsystem.dto.AuthDTO.*;
import com.example.authsystem.model.LoginStats;
import com.example.authsystem.model.User;
import com.example.authsystem.repository.LoginStatsRepository;
import com.example.authsystem.repository.UserRepository;
import com.example.authsystem.security.CustomUserDetailsService;
import com.example.authsystem.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 认证服务类
 * 提供用户注册、登录、登出和登录统计等核心功能
 * 是系统认证和授权的核心业务层实现
 */
@Service
public class AuthService {

    /**
     * 用户数据访问层接口，用于用户相关的数据库操作
     */
    @Autowired
    private UserRepository userRepository;

    /**
     * 登录统计数据访问层接口，用于记录和查询登录信息
     */
    @Autowired
    private LoginStatsRepository loginStatsRepository;

    /**
     * 密码加密工具，用于安全存储用户密码
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 认证管理器，用于处理用户身份验证
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * JWT令牌工具类，用于生成和验证认证令牌
     */
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    /**
     * 自定义用户详情服务，用于加载用户信息
     */
    @Autowired
    private CustomUserDetailsService userDetailsService;

    /**
     * 当前在线用户数量计数器
     * 使用AtomicInteger保证线程安全
     */
    private final AtomicInteger currentOnlineCount = new AtomicInteger(0);

    /**
     * 用户注册功能
     * 检查用户名和邮箱唯一性，创建新用户并生成JWT令牌
     * 
     * @param request 注册请求对象，包含用户名、密码和邮箱
     * @return 认证响应对象，包含生成的JWT令牌和用户信息
     * @throws RuntimeException 如果用户名或邮箱已存在
     */
    public AuthResponse register(RegisterRequest request) {
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new RuntimeException("Username already exists");
        }

        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new RuntimeException("Email already exists");
        }

        // 创建新用户
        User user = new User();
        user.setUsername(request.getUsername());
        user.setPassword(passwordEncoder.encode(request.getPassword())); // 密码加密存储
        user.setEmail(request.getEmail());
        user.setRole("USER"); // 默认角色为普通用户
        
        User savedUser = userRepository.save(user);
        
        // 生成JWT令牌
        UserDetails userDetails = userDetailsService.loadUserByUsername(savedUser.getUsername());
        String token = jwtTokenUtil.generateToken(userDetails);
        
        // 构建响应对象
        AuthResponse response = new AuthResponse();
        response.setToken(token);
        response.setUsername(savedUser.getUsername());
        response.setRole(savedUser.getRole());
        
        return response;
    }

    /**
     * 用户登录功能
     * 验证用户身份，更新登录时间，记录登录信息，生成JWT令牌
     * 
     * @param request 登录请求对象，包含用户名和密码
     * @param httpRequest HTTP请求对象，用于获取客户端IP和用户代理信息
     * @return 认证响应对象，包含生成的JWT令牌和用户信息
     * @throws org.springframework.security.authentication.BadCredentialsException 如果用户名或密码错误
     */
    public AuthResponse login(LoginRequest request, HttpServletRequest httpRequest) {
        // 使用Spring Security的认证管理器进行身份验证
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
        );
        
        // 将认证信息设置到安全上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);
        
        // 从认证对象中获取用户详情并生成JWT令牌
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        String token = jwtTokenUtil.generateToken(userDetails);
        
        // 从用户详情中获取用户实体
        User user = userRepository.findByUsername(request.getUsername()).orElseThrow(() -> new RuntimeException("User not found"));
        
        // 更新用户最后登录时间
        user.setLastLogin(new Date());
        userRepository.save(user);
        
        // 记录登录统计信息
        recordLoginStats(user, httpRequest);
        
        // 增加在线用户计数
        currentOnlineCount.incrementAndGet();
        
        // 构建响应对象
        AuthResponse response = new AuthResponse();
        response.setToken(token);
        response.setUsername(user.getUsername());
        response.setRole(user.getRole());
        
        return response;
    }

    /**
     * 记录用户登录统计信息
     * 创建登录记录实体，设置相关信息并保存到数据库
     * 
     * @param user 登录的用户对象
     * @param request HTTP请求对象，用于获取客户端信息
     */
    private void recordLoginStats(User user, HttpServletRequest request) {
        LoginStats loginStats = new LoginStats();
        loginStats.setUserId(user.getId());
        loginStats.setUsername(user.getUsername());
        loginStats.setIp(request.getRemoteAddr()); // 获取客户端IP地址
        loginStats.setUserAgent(request.getHeader("User-Agent")); // 获取用户代理信息
        loginStatsRepository.save(loginStats);
    }

    /**
     * 获取今日登录人数统计
     * 计算从今天00:00:00开始到当前时间的独立登录用户数
     * 
     * @return 今日独立登录用户数量
     */
    public Long getTodayLoginCount() {
        // 设置时间为今天凌晨
        Date today = new Date();
        today.setHours(0);
        today.setMinutes(0);
        today.setSeconds(0);
        
        // 查询从今天凌晨开始的独立登录用户数
        return loginStatsRepository.countDistinctUsersByDate(today);
    }

    /**
     * 获取当前在线用户数量
     * 从计数器中读取当前在线用户数
     * 
     * @return 当前在线用户数量
     */
    public int getCurrentOnlineCount() {
        return currentOnlineCount.get();
    }

    /**
     * 获取最近的登录记录
     * 按照默认排序获取最新的登录记录列表
     * 
     * @param limit 要获取的记录数量限制
     * @return 指定数量的最近登录记录列表
     */
    public List<LoginStats> getRecentLoginRecords(int limit) {
        List<LoginStats> records = loginStatsRepository.findAll();
        // 确保不会超出列表实际大小
        return records.subList(0, Math.min(limit, records.size()));
    }

    /**
     * 用户登出功能
     * 减少在线用户计数
     * 注意：在实际生产环境中，可能还需要添加token黑名单等功能
     */
    public void logout() {
        currentOnlineCount.decrementAndGet();
        // 可以在这里添加额外的登出逻辑，如将token加入黑名单等
    }
}